package CodeGenerator;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Scanner;

import Parser.NonTerminal;
import Parser.Parser;
import Parser.Symbol;
import SemanticAnalyzer.semanticAnalyzer;

/**
 * 
 * @author vcolegro, akanter
 *
 */


//TODO movl vs leal
//TODO increment/decrement being weird
//TODO '!' and '-' being weird
//TODO set the place of '&' expressions?
public class Generator {
	File file;
	FileWriter fwriter;
	StringBuffer staticdecls;
	ArrayList<HashMap<String, String>> symTab;
	int depth = 0;
	int labelno = 1;
	StringBuffer postfix;
	String jumptype; //for use with relational expressions and which jump should be used
	String jumplabel; //label to jump to if statement is false
	String retlabel;
	
	
	public static void main(String[] args){
		if (args.length!=1){
			System.out.println("Error: " + Arrays.deepToString(args) + "\nUsage: Generator filename\n filename, the full filepath to the C source file to compile");
			return;
		}
		else if(!args[0].endsWith(".c") && !args[0].endsWith(".C")){
			System.out.println("Error: " + Arrays.deepToString(args) + "\nThe file extension must be either .c or .C\nUsage: Generator filename\n filename, the full filepath to the C source file to compile");
			return;
		}
		try {
			Parser parser = new Parser(args[0]);
			Symbol root = parser.root;
			root = parser.parse(new NonTerminal("program"));
			semanticAnalyzer s = new semanticAnalyzer(root);
			if (s.hasErrors()){
				System.err.println("Errors found. Code generation will not continue.");
				System.exit(-1);
			}
			File out = new File(args[0].subSequence(0, args[0].length()-2)+".s");
			Generator gen = new Generator(out);
			gen.prelim();
			gen.generate(root);
			gen.fwriter.append(gen.staticdecls.toString());
			gen.fwriter.close();
			Scanner scan = new Scanner(out);
			while(scan.hasNextLine()){
				System.out.println(scan.nextLine());
			}
		} catch (IOException e) {
			System.err.println("File "+args[0]+" Not Found!");
		}
	}
	
	Generator(File file){
		this.file = file;
		staticdecls=new StringBuffer();
		postfix = new StringBuffer();
		symTab = new ArrayList<HashMap<String, String>>();
		symTab.add(new HashMap<String, String>());
	}

	/**
	 * Adds preliminary lines of intel assemb.
	 * @throws IOException
	 */
	void prelim() throws IOException{
		fwriter = new FileWriter(file);
		fwriter.write("\t.file\t\""+ file.getName().subSequence(0, file.getName().length()-2) +".c\"");
		fwriter.write("\n\t.text\n");
	}

	/**
	 * Traverses tree, generating code as it goes
	 * @param root
	 * @throws IOException 
	 */
	void generate(Symbol root) throws IOException{
		if(root.isTerminal()){
			if(root.type==0){ //if symbol is identifier
    			int searchD = depth; 
    			while(searchD>=0){
    				if(symTab.get(searchD).containsKey(root.getContent())){ //check if variable is in the table
    					root.place = symTab.get(searchD).get(root.getContent());
    					break;
    				}
    				searchD--;
    			}
			}
			else if (root.type==6){ //if symbol is a float
				root.place="$0x"+Integer.toHexString(Float.floatToRawIntBits(Float.parseFloat(root.getContent()))); //sets place to the hex-string representation of a float
			}
			else if(root.type==7 || root.type==8){ //if symbol is any other number (int, hex)
				root.place="$"+root.getContent();
			}
			else root.place=root.getContent();
		}
		else {
			if(root.getContent().equals("var-declaration")){ //Adds static var-declarations to separate stringbuffer to be appended at the end of the code generataion
				for(Symbol elt : root.getChildren()){
					generate(elt);
				}
				int pointermod = 0;
				if(root.getChildren().size()==4) pointermod = 1;
				int mul = 1;
				int align = 4;
				if(root.getChildren().size()>4) mul = Integer.parseInt(root.getChildren().get(3).getContent());  //if the var-declaration is an array, then the size is larger
				if (mul>=32) align = 32;
				staticdecls.append("\t.comm\t"+root.getChildren().get(1+pointermod).getContent()+','+4*mul+','+align+'\n');
				symTab.get(depth).put(root.getChildren().get(1+pointermod).getContent(), root.getChildren().get(1+pointermod).getContent());
			}
			
			else if(root.getContent().equals("fun-declaration")){
				int pointermod = 0;
				if(root.getChildren().size()>6) pointermod = 1;
				String funcname = root.getChildren().get(1+pointermod).getContent();
				retlabel = funcname+"ret";
				fwriter.append(".globl " + funcname +"\n");
				emit(".type",funcname, "@function");
				emitLabel(funcname);
				emit("pushl", "%ebp");
				emit("movl", "%esp", "%ebp");
				depth++; //for symbol-table
				symTab.add(depth, new HashMap<String,String>());
				emit("subl", "$" + (getFrameLength(root)+callSpace(root.getChildren().get(root.getChildren().size()-1))),"%esp");
				emit("andl", "$-16","$esp");
				processParams(root.getChildren().get(3+pointermod));
				generate(root.getChildren().get(5+pointermod).getChildren().get(root.getChildren().get(5+pointermod).getChildren().size()-2));  //selects the compound statement's 2nd to last child
				symTab.remove(depth);
				depth--; //for symbol-table
				emitLabel(retlabel);
				emit("leave");
				emit("ret");
				emit(".size",funcname, ".-"+funcname);
			}
			
			else if(root.getContent().equals("expression")){
				//boolean firstSE = false;
				for(int i=0;i<root.getChildren().size();i+=2){
					Symbol elt = root.getChildren().get(i);
					generate(elt);
					if(!(elt.getType()>=6 && elt.getType()<9)){ //if child is a constant, do not push it to stack
						emit("pushl",elt.place);
						//if (i == root.getChildren().size()-1) firstSE = true;
					}
				}

				int pos = root.getChildren().size()-3; //process from right to left
				String op;
				
				//puts first term in %eax
/*				if(firstSE){
					emit("popl","%ebx");
				}else{
					emit("movl", root.getChildren().get(pos+2).place, "%ebx");
				}
*/
				for (;pos>=0;pos-=2){
					if(root.getChildren().get(pos+1).matches("=")) op = "movl";
					else if(root.getChildren().get(pos+1).matches("+=")) op = "addl";
					else op = "subl";

					if((root.getChildren().get(pos+2).getType()>=6 && root.getChildren().get(pos+2).getType()<9)){ //if we are dealing with constants
						emit("movl", root.getChildren().get(pos+2).place, "%ebx");
					}
					else{ //if the value comes from the stack
						emit("popl", "%ebx");
					}

//					if(!op.equals("movl")){ //if += or -=
						if((root.getChildren().get(pos).getType()>=6 && root.getChildren().get(pos).getType()<9)){ //if we are dealing with constants
							emit("movl", root.getChildren().get(pos).place, "%eax");
						}
						else{ //if the value comes from the stack
							emit("popl", "%eax");
						}
//					}
					
					String ebx = "%ebx";
					if (root.getChildren().get(pos+2).deRef) //if RHS of expression is a dereferenced pointer, the pointer is dereferenced =)
						ebx='('+ebx+')';
					emit(op,ebx,"%eax");		
					String newplace = root.getChildren().get(pos).place;
					if (root.getChildren().get(pos).deRef){ //if the LHS of expression is a dereferenced pointer, the pointer is dereferenced =)
						newplace="(%ecx)";
						emit("movl", root.getChildren().get(pos).place, "%ecx"); //moves pointer to %ecx
					}
					emit("movl","%eax",newplace);
					root.place="%eax";
				}
			}

			else if (root.getContent().equals("expression-stmt")){
				generate(root.getChildren().get(0));
				if(postfix.length()>0){
					fwriter.append(postfix.toString());
					postfix.delete(0,postfix.length());
				}
				
			}
			
			else if(root.getContent().equals("if-stmt")){
				//If-else
				if(root.getChildren().size()>5){
					String label1 = generateLabel();
					String label2 = generateLabel();
					jumplabel=label1;
					generate(root.getChildren().get(2));
					//this will set conditional flags
					//emit(jumptype, label1);
					generate(root.getChildren().get(4));
					emit("jmp",label2);
					emitLabel(label1);
					generate(root.getChildren().get(6));
					emitLabel(label2);
				}
				//If
				else{
					String label1 = generateLabel();
					jumplabel=label1;
					generate(root.getChildren().get(2));
					//emit(jumptype, label1);
					generate(root.getChildren().get(4));
					emitLabel(label1);
				}
				
				if(postfix.length()>0){
					fwriter.append(postfix.toString());
					postfix.delete(0,postfix.length());
				}
			}
			
			else if(root.getContent().equals("while-stmt")){
				String label1 = generateLabel();
				String label2 = generateLabel();
				emitLabel(label1);
				jumplabel=label2;
				generate(root.getChildren().get(2));
				generate(root.getChildren().get(4));			
				if(postfix.length()>0){
					fwriter.append(postfix.toString());
					postfix.delete(0,postfix.length());
				}
				emit("jmp", label1);
				emitLabel(label2);
			}
			
			else if(root.getContent().equals("return-stmt")){
				if(root.getChildren().size()>2){
					generate(root.getChildren().get(1));
					emit("movl", root.getChildren().get(1).place, "%eax");
				}
				emit("jmp", retlabel);
				if(postfix.length()>0){
					fwriter.append(postfix.toString());
					postfix.delete(0,postfix.length());
				}
			}
			
			else if(root.getContent().equals("for-stmt")){
				String label1 = generateLabel();
				String label2 = generateLabel();
				generate(root.getChildren().get(2));  //Either the first optional-expression or ';'
				emitLabel(label1);
				jumplabel=label2;
				if(root.getChildren().get(2).place.equals("semic")){ //evaluate the conditional expression
					generate(root.getChildren().get(3));
				}
				else generate(root.getChildren().get(4));
				generate(root.getChildren().get(root.getChildren().size()-1)); //evaluate the actual statement
				generate(root.getChildren().get(root.getChildren().size()-3));
				if(postfix.length()>0){
					fwriter.append(postfix.toString());
					postfix.delete(0,postfix.length());
				}
				emit("jmp", label1);
				emitLabel(label2);
			}
			
			else if (root.getContent().equals("and-expr")){
				for (int pos = 0;pos<=root.getChildren().size();pos+=2){
					generate(root.getChildren().get(pos));
					if((root.getChildren().get(pos).type>=6 && root.getChildren().get(pos).type<9) || root.getChildren().get(pos).type==0){
						emit("movl", root.getChildren().get(pos).place, "%eax");
						emit("testl","%eax", "%eax"); //if a 0, unconditionally jump to the "false" branch
						emit("jne", jumplabel);
						continue;
					}
					else if(root.getChildren().get(pos).deRef){
						emit("movl", root.getChildren().get(pos).place, "%eax");
						emit("movl", "(%eax)", "%eax");
						emit("testl","%eax", "%eax"); //if a 0, unconditionally jump to the "false" branch
						emit("jne", jumplabel);
						continue;
					}
					emit(jumptype,jumplabel);
				}
				root.place="%eax";
			}
			
			else if (root.getContent().equals("or-expr")){
				String shortcircuitlabel = generateLabel();
				int pos = 0;
				for (;pos<=root.getChildren().size()-2;pos+=2){
					generate(root.getChildren().get(pos));
					if((root.getChildren().get(pos).type>=6 && root.getChildren().get(pos).type<9) || root.getChildren().get(pos).type==0){
						emit("movl", root.getChildren().get(pos).place, "%eax");
						emit("testl","%eax", "%eax"); //if a 0, unconditionally jump to the "false" branch
						emit("je", shortcircuitlabel);
						continue;
					}
					else if(root.getChildren().get(pos).deRef){
						emit("movl", root.getChildren().get(pos).place, "%eax");
						emit("movl", "(%eax)", "%eax");
						emit("testl","%eax", "%eax"); //if a 0, unconditionally jump to the "false" branch
						emit("je", shortcircuitlabel);
						continue;
					}
					emit(jumpInvert(jumptype),shortcircuitlabel);
				}
				generate(root.getChildren().get(pos));
				if((root.getChildren().get(pos).type>=6 && root.getChildren().get(pos).type<9) || root.getChildren().get(pos).type==0){
					emit("movl", root.getChildren().get(pos).place, "%eax");
					emit("testl","%eax", "%eax"); //if a 0, unconditionally jump to the "false" branch
					emit("jne", jumplabel);
				}
				else if(root.getChildren().get(pos).deRef){
					emit("movl", root.getChildren().get(pos).place, "%eax");
					emit("movl", "(%eax)", "%eax");
					emit("testl","%eax", "%eax"); //if a 0, unconditionally jump to the "false" branch
					emit("jne", jumplabel);
				}
				else emit(jumptype,jumplabel);
				root.place="%eax";
				emitLabel(shortcircuitlabel);
			}
			
			else if (root.getContent().equals("relational-expr")){
				for(Symbol elt : root.getChildren()){
					generate(elt);
				}
				int pos = 0;
				String op;
				emit("movl",root.getChildren().get(pos).place,"%eax");
				if(root.getChildren().get(pos).deRef){ //if it's a dereferenced pointer, we need to dereference it to do any operations
					emit("movl", "(%eax)", "%eax");
				}
				for (;pos<=root.getChildren().size()-4;pos+=2){
					emit("cmpl",root.getChildren().get(pos+2).place, "%eax");
					if(root.getChildren().get(pos+1).matches("<=")) op = "setle";
					else if(root.getChildren().get(pos+1).matches("<")) op = "setl";
					else if(root.getChildren().get(pos+1).matches(">=")) op = "setge";
					else if(root.getChildren().get(pos+1).matches(">")) op = "setg";
					else if(root.getChildren().get(pos+1).matches("==")) op = "sete";
					else op = "setne";
					emit(op,"%al");
					emit("movzbl", "%al", "%eax");
				}
				String place2 = root.getChildren().get(pos+2).place;
				if(root.getChildren().get(pos+2).deRef){ //if it's a dereferenced pointer, we need to dereference it to do any operations
					emit("movl", place2, "%ebx");
					emit("movl", "(%ebx)", "%ebx");
					place2="%ebx";
				}
				emit("cmpl",place2, "%eax");
				if(root.getChildren().get(pos+1).matches("<=")) jumptype = "jg";
				else if(root.getChildren().get(pos+1).matches("<")) jumptype = "jge";
				else if(root.getChildren().get(pos+1).matches(">=")) jumptype = "jl";
				else if(root.getChildren().get(pos+1).matches(">")) jumptype = "jle";
				else if(root.getChildren().get(pos+1).matches("==")) jumptype = "jne";
				else jumptype = "je";
				emit(jumptype,jumplabel);
				root.place="%eax";
			}
			
			else if (root.getContent().equals("additive-expr")){
				boolean firstSE=false; //whether the first child is a subexpression
				for(int i = root.getChildren().size()-1; i>=0; i-=2){
					generate(root.getChildren().get(i));
					if(!(root.getChildren().get(i).getType()>=6 && root.getChildren().get(i).getType()<9)){ //if child is a constant, do not push it to stack
						if (root.getChildren().get(i).deRef){
							emit("movl", root.getChildren().get(i).place, "%eax");
							emit("pushl","(%eax)");
						}
						else emit("pushl",root.getChildren().get(i).place);
						if(i==0)
							firstSE=true;
					}
				}
				
				int pos = 0;
				String op;
				
				//puts first term in %eax
				if(firstSE){
					emit("popl","%eax");
				}else{
					emit("movl", root.getChildren().get(pos).place, "%eax");
				}
				for (;pos<=root.getChildren().size()-2;pos+=2){
					if(root.getChildren().get(pos+1).matches("+")) op = "addl";
					else op = "subl";
					if((root.getChildren().get(pos+2).getType()>=6 && root.getChildren().get(pos+2).getType()<9)){ //if we are dealing with constants
						emit(op,root.getChildren().get(pos+2).place,"%eax");
					}
					else{
						emit("popl", "%ebx");
						emit(op,"%ebx","%eax");
					}
				}
				root.place="%eax";
			}
			
			else if (root.getContent().equals("term")){
				boolean firstSE=false; //whether the first child is a subexpression
				for(int i = root.getChildren().size()-1; i>=0; i-=2){
					generate(root.getChildren().get(i));
					if(!(root.getChildren().get(i).getType()>=6 && root.getChildren().get(i).getType()<9)){ //if child is a constant, do not push it to stack
						if (root.getChildren().get(i).deRef){
							emit("movl", root.getChildren().get(i).place, "%eax");
							emit("pushl","(%eax)");
						}
						else emit("pushl",root.getChildren().get(i).place);
						if(i==0)
							firstSE=true;
					}
				}
				int pos = 0;
				String op;
				
				//puts first term in %eax
				if(firstSE){
					emit("popl","%eax");
				}else{
					emit("movl", root.getChildren().get(pos).place, "%eax");
				}
				
				for (;pos<=root.getChildren().size()-2;pos+=2){
					if(root.getChildren().get(pos+1).matches("*")){
						op = "imull";
						if((root.getChildren().get(pos+2).getType()>=6 && root.getChildren().get(pos+2).getType()<9)){ //if we are dealing with constants
							emit(op,root.getChildren().get(pos+2).place,"%eax");
						}
						else{
							emit("popl", "%ebx");
							emit(op,"%ebx","%eax");
						}
					}
					else{
						op = "idivl"; //this is signed divide
						
						if((root.getChildren().get(pos+2).getType()>=6 && root.getChildren().get(pos+2).getType()<9)){ //if we are dealing with constants
							emit("cltd");
							emit("movl", root.getChildren().get(pos+2).place, "%ebx");
							emit(op,"%ebx");
						}
						else{
							emit("cltd");
							emit("popl", "%ebx");
							emit(op,"%ebx");
						}
						
					}

					if(root.getChildren().get(pos+1).matches("%")){ //if doing % operation, we move the remainder (placed in %edx) to %eax
						emit("movl","%edx","%eax");
					}
				}
				root.place="%eax";
			}
			
			else if(root.getContent().equals("unary-expr")){ //TODO '!' and '-' don't work quite right...
				generate(root.getChildren().get(1));
				if(root.getChildren().get(0).matches("*")){
					//emit("movl", root.getChildren().get(1).place, "%eax");
					//emit("movl","(" + root.getChildren().get(1).place + ")", "%eax");
					root.place=root.getChildren().get(1).place;
					root.deRef=true;
					//root.place="(%eax)";
				}
				if(root.getChildren().get(0).matches("&")){
					emit("leal",root.getChildren().get(1).place, "%eax");
					root.place="%eax";  //TODO this might be wrong
				}
				else if(root.getChildren().get(0).matches("!")){
					emit("notl",root.getChildren().get(1).place, "%eax");
					if((root.getChildren().get(1).getType()>=6 && root.getChildren().get(1).getType()<9)){ //if we are dealing with constants
						if(root.getChildren().get(1).place.equals("$0"))
							root.place="$1";
						else root.place="$0";
					}
					else root.place="%eax";
				}
				else if(root.getChildren().get(0).matches("-")){
					emit("negl",root.getChildren().get(1).place, "%eax");
					if((root.getChildren().get(1).getType()>=6 && root.getChildren().get(1).getType()<9)){ //if we are dealing with constants
						root.getChildren().get(1).place="$" + ((-1) * Integer.parseInt(root.getChildren().get(1).place.substring(1)));
					}
					root.place="%eax";
				}
				
			}
			
			else if (root.getContent().equals("postfix-expr")){  //TODO is this a reasonable way to increment?
				generate(root.getChildren().get(0));
				String place = root.getChildren().get(0).place;
				if(root.getChildren().get(0).deRef){
					postfix.append("\tmovl\t" + root.getChildren().get(0).place + ", %eax");
					place = "(%eax)";
				}
				if (root.getChildren().get(root.getChildren().size()-1).getContent().equals("++")){
					postfix.append("\tleal\t"+ place + ", %eax\n\tincl\t(%eax)\n");
					root.place=root.getChildren().get(0).place;
				}
				else if (root.getChildren().get(root.getChildren().size()-1).getContent().equals("--")){
					postfix.append("\tleal\t"+ place + ", %eax\n\tdecl\t(%eax)\n");
					root.place=root.getChildren().get(0).place;
				}
				else{
/*					emit("leal",root.getChildren().get(0).place,"%eax");
					generate(root.getChildren().get(2));
					emit("addl", ""+ 4* Integer.parseInt(root.getChildren().get(2).place), "%eax");*/
					generate(root.getChildren().get(2));
					
					if(symTab.get(0).containsValue(root.getChildren().get(0).place)){  //if variable is global
						root.place= root.getChildren().get(0).place + "+" + 4* Integer.parseInt(root.getChildren().get(2).place);
					}
					else{
						//removes original number from place, adds the offset to it, and sets root.place to that
						int temp = Integer.parseInt(root.getChildren().get(0).place.substring(0, root.getChildren().get(0).place.indexOf('(')));
						int temp2;
						if(root.getChildren().get(2).type>5 && root.getChildren().get(2).type<9){
							temp2 = 4* Integer.parseInt(root.getChildren().get(2).place.substring(1));
						}
						else{
							temp2 = Integer.parseInt(root.getChildren().get(2).place.substring(0, root.getChildren().get(2).place.indexOf('(')));
						}
						temp+=temp2;
						String suffix = root.getChildren().get(0).place.substring(root.getChildren().get(0).place.indexOf('('), root.getChildren().get(0).place.length());
						root.place=temp + suffix;
					}
				}
			}
			else if(root.getContent().equals("call")){
				if(root.getChildren().size()>3){
					int argsize;
					if(root.getChildren().get(2).getChildren()!=null)
						argsize= ((root.getChildren().get(2).getChildren().size()/2)+1)*4;
					else argsize=4;
					emit("subl","$"+argsize, "%esp");
					if(root.getChildren().get(2).getContent().equals("arg-list")){  //if there is a list of arguments
						for(int i = root.getChildren().get(2).getChildren().size()-1;i>=0;i-=2){
							generate(root.getChildren().get(2).getChildren().get(i));
							if(symTab.get(0).containsKey(root.getChildren().get(2).getChildren().get(i).place) && !root.getChildren().get(2).getChildren().get(i).deRef){ //if argument is a global variable
								emit("leal",root.getChildren().get(2).getChildren().get(i).place,"%eax");
								emit("pushl","%eax");
							}
							else if(root.getChildren().get(2).getChildren().get(i).deRef){
								emit("movl", root.getChildren().get(2).getChildren().get(i).place, "%eax");
								emit("pushl", "(%eax)");
							}else emit("pushl",root.getChildren().get(2).getChildren().get(i).place);
						}
					}
					else{  //if there is a single argument
						generate(root.getChildren().get(2));
						if(symTab.get(0).containsKey(root.getChildren().get(2).place) && !root.getChildren().get(2).deRef){ //if argument is a global variable
							emit("leal",root.getChildren().get(2).place,"%eax");
							emit("pushl","%eax");
						}
						else if(root.getChildren().get(2).deRef){
							emit("movl", root.getChildren().get(2).place, "%eax");
							emit("pushl", "(%eax)");
						} 
						else emit("pushl",root.getChildren().get(2).place);
					}
					emit("call",root.getChildren().get(0).getContent());
					emit("addl", "$16", "%esp");
				}
				root.place="%eax";
			}
			else
			{
				for(Symbol elt : root.getChildren()){
					generate(elt);
				}
			}
			
			
		}
	}
	
	void emit(String...pieces) throws IOException{
		if(pieces.length==3 && pieces[0].equals("movl") && pieces[1].equals(pieces[2])){  //don't emit "movl, x, x" for any x
			return;
		}
		StringBuffer sb = new StringBuffer();
		sb.append('\t'+pieces[0]);
		if (pieces.length>1){
			sb.append('\t'+pieces[1]);
			if(pieces.length>2)
				sb.append(", " + pieces[2]);
		}
		sb.append('\n');
		fwriter.append(sb.toString());
	}
	
	/**
	 * 
	 * @param root the fun-declaration symbol
	 * @return the length for the stack
	 * ALSO adds local-declarations to the symbolTable
	 */
	int getFrameLength(Symbol root){
		boolean hasReturn = !root.getChildren().get(0).getContent().equals("void");
		int ret = 0;
		Symbol curr = root.getChildren().get(root.getChildren().size()-1); //curr = compound-statement node
		if(curr.getChildren().get(1).matches("local-declarations")){
			curr= curr.getChildren().get(1);
			HashMap<String,String> hm = symTab.get(depth);
			for(Symbol elt : curr.getChildren()){
				//add variable sizes to ret; array sizes need to be calculated. individual variables are just 4
				if (elt.getChildren().size()>4){
					ret+= Integer.parseInt(elt.getChildren().get(3).getContent())*4;
					hm.put(elt.getChildren().get(1).getContent(),"-" + (ret)+ "(%ebp)");
				}
				else {
					int pointermod = 0;
					if(elt.getChildren().size()==4) pointermod=1; //if this is a pointer var-declaration, the ID is in the next slot
					ret+=4;
					hm.put(elt.getChildren().get(1+pointermod).getContent(),"-" +(ret)+ "(%ebp)");
				}
			}
		}
		else if (curr.getChildren().get(1).matches("var-declaration")){
			curr= curr.getChildren().get(1);
			HashMap<String,String> hm = symTab.get(depth);
			if (curr.getChildren().size()>4){
				ret+= Integer.parseInt(curr.getChildren().get(3).getContent())*4;
				hm.put(curr.getChildren().get(1).getContent(),"-" +(ret)+ "(%ebp)");
			}
			else{
				ret+=4;
				hm.put(curr.getChildren().get(1).getContent(),"-" +(ret)+ "(%ebp)");
			}
		}
		if((ret%16)!=0) ret+=(16-(ret%16)); //always allocate stack variables in multiples of 16
		if(hasReturn) ret+=4; //add 4 if there is a return
		return ret;
	}
	
	/**
	 * Provides a size modification to the stack-frame if there is a method call within this function
	 * @param root, the tree to search through
	 * @return
	 */
	
	int callSpace(Symbol root){
		if (root.getContent().equals("call")) return 8;
		int ret=0;
		int temp;
		if(root.getChildren()!=null)
			for(Symbol elt : root.getChildren()){
			temp = callSpace(elt);
			if (ret<temp) ret = temp;
		}
		return ret;
	}
	
	/**
	 * 
	 * @param root the param/param-list root node from a fun-declaration
	 */
	
	void processParams(Symbol root){
		if(root.getContent().equals("void")){
			return;
		}
		int count = 4;
		HashMap<String,String> hm = symTab.get(depth);

		if(root.getContent().equals("param")){
			count+=4;
			hm.put(root.getChildren().get(1).getContent(),count + "(%ebp)");
		}
		else{
			for(Symbol elt : root.getChildren()){
				if(!elt.getContent().equals("comma")){
					count+=4;
					hm.put(elt.getChildren().get(1).getContent(),count + "(%ebp)");
				}
			}
		}
	}

	String generateLabel(){
		return "L"+labelno++;
	}
	
	void emitLabel(String label) throws IOException{
		fwriter.append(label+":\n");
	}
	
	String jumpInvert(String jump){
		String ret;
		if(jumptype.equals("jg"))
				ret = "jle";
		else if(jumptype.equals("jge"))
			ret = "jl";
		else if(jumptype.equals("jle"))
			ret = "jg";
		else if(jumptype.equals("jl"))
			ret = "jge";
		else if(jumptype.equals("je"))
			ret = "jne";
		else //(jumptype.equals("jne"))
			ret = "je";
		return ret;
	}
}
